//
// Created by haoy on 2017/4/29.
//

#ifndef RTC_XSWITCH2_TIMELINE_HPP
#define RTC_XSWITCH2_TIMELINE_HPP

#include <iomanip>
#include <iostream>
#include <set>
#include <sstream>

#include "clock.hpp"

namespace benchmark {

class Timeline {
public:
    Timeline(Clock::duration rowResolution) : _rowResolution(rowResolution) {}

    template <class Value>
    void addValue(const std::string& columnName, Value value) {
        std::ostringstream writer;
        auto now = Clock::now();

        if (_rows.empty() || (now - _rowResolution > _last_rolled_time)) {
            _rows.push_back(Row());
            _last_rolled_time = now;
        }
        Row& currentRow = *_rows.rbegin();
        writer << value;
        currentRow[columnName] = writer.str();
        _columnNames.insert(columnName);
    }

    std::string toString() {
        std::ostringstream writer;
        writer << "===================================================================================" << std::endl;
        writer << std::setw(10) << "seconds";
        for (auto& cn : _columnNames) {
            writer << " " << std::setw(10) << std::right << cn;
        }
        writer << std::endl;
        for (int i = 0; i < _rows.size(); ++i) {
            auto& row = _rows[i];
            writer << std::setw(10) << std::right << i;
            for (auto& cn : _columnNames) {
                writer << " " << std::setw(10) << std::right << row[cn];
            }
            writer << std::endl;
        }
        writer << "===================================================================================" << std::endl;
        return std::string(writer.str());
    }

private:
    Clock::duration _rowResolution;
    std::set<std::string> _columnNames;

    typedef std::map<std::string, std::string> Row;

    std::vector<Row> _rows;
    Clock::time_point _last_rolled_time;
};

}

std::ostream& operator<< (std::ostream& os, benchmark::Timeline& tt) {
    os << tt.toString();
    return os;
}

#endif //RTC_XSWITCH2_TIMELINE_HPP
